#pragma once

#include "Thread.hpp"
#include "LockGuard.hpp"
#include <vector>
#include <queue>
#include <pthread.h>
#include <unistd.h>

using namespace ThreadNs;

const int gnum = 5;

template <class T>
class ThreadPool
{
private:
    static void *handlerTask(void *args)
    {
        ThreadPool<T> *threadpool = static_cast<ThreadPool<T> *>(args);
        threadpool->lockQueue();
        while (true)
        {
            while(threadpool->isQueueEmpty())
            {
                threadpool->threadWait();
            }
            T t = threadpool->pop();
            threadpool->unlockQueue();
            // t.();
        }
        return nullptr;
    }
public:
    void lockQueue() { pthread_mutex_lock(&_mutex); }
    void unlockQueue() { pthread_mutex_unlock(&_mutex); }
    bool isQueueEmpty() { return _task_queue.empty(); }
    void threadWait() { pthread_cond_wait(&_cond, &_mutex); }
    T pop() 
    { 
        T t = _task_queue.front();
        _task_queue.pop();
        return t;
    }
public:
    ThreadPool(const int &num = gnum) : _num(num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
        for (int i = 0; i < _num; ++i)
        {
            _threads.push_back(new Thread(handlerTask, this));
        }
    }
    void run()
    {
        for (const auto &t : _threads)
        {
            t->start();
            std::cout << t->threadname() << " start..." << std::endl;
        }
    }
    void push(const T &in)
    {
        pthread_mutex_lock(&_mutex);
        _task_queue.push(in);
        pthread_cond_signal(&_cond);
        pthread_mutex_unlock(&_mutex);
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
        for (auto &t : _threads)
            delete t;
    }

private:
    int _num;
    std::vector<Thread *> _threads;
    std::queue<T> _task_queue;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;
};